package com.org.devg.monitor.server.api;


import org.devgframwork.es5.elasticserach.EsResult;
import org.devgframwork.es5.elasticserach.EsSearch;
import com.org.devg.monitor.server.model.JsonModel;
import com.org.devg.monitor.server.model.MonitorMessageDO;
import org.devgframwork.platform.utils.CommonUtil;
import org.devgframwork.platform.utils.LocalDateUtil;
import io.searchbox.core.search.aggregation.*;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Api(value = "/admin/index", tags = "首页")
@Slf4j
@RestController
public class MonitorIndexController {

    @GetMapping(value = {"/admin/monitor/index.htm"})
    public ModelAndView index() {
        Map<String, Object> result = new HashMap<>();
        result.put("name", "杜恒");
        return new ModelAndView("/admin/index", result);
    }

    @GetMapping(value = {"/admin/monitor/welcome.htm"})
    public ModelAndView welcome() {
        return new ModelAndView("/admin/welcome");
    }

    @GetMapping(value = {"/admin/monitor/messageList.htm"})
    public ModelAndView messageList() {
        String theDate = LocalDateUtil.localDateFormat(LocalDate.now(), LocalDateUtil.FORMAT_PATTERN3);
        Map<String, Object> result = new HashMap<>();
        result.put("theDate", theDate);
        return new ModelAndView("/admin/messageList", result);
    }

    @PostMapping("/admin/monitor/messagePageSearch")
    public JsonModel messagePageSearch(@RequestBody Map<String, Object> params) throws Exception {

        Integer pageNum = CommonUtil.isNullOrEmpty(params.get("page")) ? 1 : Integer.parseInt(params.get("page").toString());
        Integer pageSize = CommonUtil.isNullOrEmpty(params.get("limit")) ? 10 : Integer.parseInt(params.get("limit").toString());

        List<MonitorMessageDO> resultList = new ArrayList<>();

        String theDate = CommonUtil.getMapString(params, "theDate");//获取传入时间
        if (CommonUtil.isNullOrEmpty(theDate)) {
            theDate = LocalDateUtil.localDateFormat(LocalDate.now(), LocalDateUtil.FORMAT_PATTERN3);
        }
        String start = CommonUtil.getMapString(params, "start");//开始时间
        if (CommonUtil.isNullOrEmpty(start)) {
            start = "00:00:01";
        }
        String end = CommonUtil.getMapString(params, "end");//结束时间
        if (CommonUtil.isNullOrEmpty(end)) {
            end = "23:59:59";
        }
        String startTime = theDate + " " + start;
        String endTime = theDate + " " + end;
        LocalDateTime startlocalDateTime = LocalDateUtil.localDateTimeParse(startTime, LocalDateUtil.FORMAT_PATTERN1);
        LocalDateTime endlocalDateTime = LocalDateUtil.localDateTimeParse(endTime, LocalDateUtil.FORMAT_PATTERN1);
        Date startDate = LocalDateUtil.localDateTimeToDate(startlocalDateTime);
        Date endDate = LocalDateUtil.localDateTimeToDate(endlocalDateTime);
        Long queryStartTime = startDate.getTime();
        Long queryEndTime = endDate.getTime();

        String queryIndex = "monitor_message_consumer_" + theDate.replace("-", "");
        String queryType = "monitor_message_consumer";

        Boolean indexTypeExists = EsSearch.indicesTypeExists(queryIndex, queryType);
        if (!indexTypeExists) {
            return JsonModel.newSuccess(resultList, 0);
        }

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 时间范围过滤
        RangeQueryBuilder reqTimeBuilder = QueryBuilders.rangeQuery("req_time").gte(queryStartTime).lte(queryEndTime);
        queryBuilder.filter(reqTimeBuilder);
//      按监控类型查询
        String messageType = CommonUtil.getMapString(params, "messageType");//监控类型
        if (!CommonUtil.isNullOrEmpty(messageType)) {
            QueryBuilder messageTypeBuilder = QueryBuilders.termQuery("message_type", messageType);
            queryBuilder.filter(messageTypeBuilder);
        }

        String modelName = CommonUtil.getMapString(params, "modelName"); // 模块名称
        if (!CommonUtil.isNullOrEmpty(modelName)) {
            QueryBuilder modelNameBuilder = QueryBuilders.termQuery("model_name.keyword", modelName);
            queryBuilder.filter(modelNameBuilder);
        }

        String evnName = CommonUtil.getMapString(params, "evnName"); // 模块名称
        if (!CommonUtil.isNullOrEmpty(evnName)) {
            QueryBuilder evnNameBuilder = QueryBuilders.termQuery("evn_name.keyword", evnName);
            queryBuilder.filter(evnNameBuilder);
        }
//      按结果类型查询
        String resultType = CommonUtil.getMapString(params, "resultType");//结果类型
        if (!CommonUtil.isNullOrEmpty(resultType)) {
            QueryBuilder resultTypeBuilder = QueryBuilders.termQuery("result_type.keyword", resultType);
            queryBuilder.filter(resultTypeBuilder);
        }

        //     按关键字查询
        String keyword = CommonUtil.getMapString(params, "keyword");
        if (!CommonUtil.isNullOrEmpty(keyword)) {
            BoolQueryBuilder searchBuilder = QueryBuilders.boolQuery();
//          方法名
            QueryBuilder classMethodBuilder = QueryBuilders.wildcardQuery("class_method.keyword", "*" + keyword + "*");
            searchBuilder.should(classMethodBuilder);
//          请求url
            QueryBuilder requestUrlBuilder = QueryBuilders.wildcardQuery("request_url.keyword", "*" + keyword + "*");
            searchBuilder.should(requestUrlBuilder);
//          消息KEY
            QueryBuilder messageKeyBuilder = QueryBuilders.wildcardQuery("message_key", "*" + keyword + "*");
            searchBuilder.should(messageKeyBuilder);

            queryBuilder.must(searchBuilder);
        }

        //    花费时长查询
        String costTimeType = CommonUtil.getMapString(params, "costTimeType");
        if (!CommonUtil.isNullOrEmpty(costTimeType)) {
            QueryBuilder costTimeBuilder = null;
            switch (costTimeType) {
                case "0":   // <=1000ms
                    costTimeBuilder = QueryBuilders.rangeQuery("costTime").lte(1000);
                    queryBuilder.filter(costTimeBuilder);
                    break;
                case "1":  // >1000ms <=3000ms
                    costTimeBuilder = QueryBuilders.rangeQuery("costTime").gt(1000).lte(3000);
                    queryBuilder.filter(costTimeBuilder);
                    break;
                case "2":  // >3000ms
                    costTimeBuilder = QueryBuilders.rangeQuery("costTime").gt(3000);
                    queryBuilder.filter(costTimeBuilder);
                    break;
                default:  // <=1000ms
                    costTimeBuilder = QueryBuilders.rangeQuery("costTime").lte(1000);
                    queryBuilder.filter(costTimeBuilder);
                    break;
            }
        }


        // 查询请求消息KEY
        String requestMessageKey = CommonUtil.getMapString(params, "requestMessageKey");
        if (!CommonUtil.isNullOrEmpty(requestMessageKey)) {
            QueryBuilder requestMessageKeyBuilder = QueryBuilders.termQuery("rquest_message_key", requestMessageKey);
            queryBuilder.filter(requestMessageKeyBuilder);
//            SortBuilder messageTypeSortBuilder = SortBuilders.fieldSort("message_type").order(SortOrder.ASC);
//            SortBuilder reqTimeSortBuilder = SortBuilders.fieldSort("req_time").order(SortOrder.DESC);
            SortBuilder messageTypeSortBuilder = SortBuilders.fieldSort("message_key").order(SortOrder.ASC);
            searchSourceBuilder.sort(messageTypeSortBuilder);
        } else {
            SortBuilder sortBuilder;
            // 只查 controllerc
            QueryBuilder messageTypeBuilder = QueryBuilders.termQuery("message_type", 1);
            queryBuilder.filter(messageTypeBuilder);
            String field = CommonUtil.getMapString(params, "field");
            String order = CommonUtil.getMapString(params, "order");
            if (!CommonUtil.isNullOrEmpty(field) && !CommonUtil.isNullOrEmpty(order)) {
                if (CommonUtil.equals(field, "costTime")) {
                    field = "cost_time";
                } else if (CommonUtil.equals(field, "startTime")) {
                    field = "req_time";
                }
                sortBuilder = SortBuilders.fieldSort(field).order(order.equals("desc") ? SortOrder.DESC : SortOrder.ASC);
            } else {
                sortBuilder = SortBuilders.fieldSort("req_time").order(SortOrder.DESC); // 默认按发布时间倒序排
            }
            searchSourceBuilder.sort(sortBuilder);
        }
        searchSourceBuilder.query(queryBuilder);
        EsResult<MonitorMessageDO> esResult = EsSearch.getEsResult(searchSourceBuilder, pageNum, pageSize, queryIndex, queryType, MonitorMessageDO.class);
        resultList = esResult.getEsResultList();
        long total = esResult.getTotal();
        return JsonModel.newSuccess(resultList, total);
    }


    @GetMapping(value = {"/admin/monitor/messageStatistics.htm"})
    public ModelAndView messageStatistics() {
        String theDate = LocalDateUtil.localDateFormat(LocalDate.now(), LocalDateUtil.FORMAT_PATTERN3);
        Map<String, Object> result = new HashMap<>();
        result.put("theDate", theDate);
        return new ModelAndView("/admin/messageStatistics", result);
    }


    @PostMapping("/admin/monitor/messageStatistics")
    public JsonModel messageStatistics(@RequestBody Map<String, Object> params) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        long total = 0;
        try {
            int viewSize = 5000;
            String theDate = CommonUtil.getMapString(params, "theDate");//获取传入时间
            if (CommonUtil.isNullOrEmpty(theDate)) {
                theDate = LocalDateUtil.localDateFormat(LocalDate.now(), LocalDateUtil.FORMAT_PATTERN3);
            }
            String queryIndex = "monitor_message_consumer_" + theDate.replace("-", "");
            String queryType = "monitor_message_consumer";
            Boolean indexTypeExists = EsSearch.indicesTypeExists(queryIndex, queryType);
            if (!indexTypeExists) {
                return JsonModel.newSuccess(resultList, 0);
            }
            String messageType = CommonUtil.getMapString(params, "messageType");//获取传入时间
            if (CommonUtil.isNullOrEmpty(messageType)) {
                messageType = "1";
            }

            String evnName = CommonUtil.getMapString(params, "evnName"); // 模块名称

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(0);
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            QueryBuilder messageTypeBuilder = QueryBuilders.termQuery("message_type", messageType); //  只统计请求访问量
            queryBuilder.must(messageTypeBuilder);
            if (!CommonUtil.isNullOrEmpty(evnName)) {
                QueryBuilder evnNameBuilder = QueryBuilders.termQuery("evn_name.keyword", evnName); //  只统计请求访问量
                queryBuilder.must(evnNameBuilder);
            }
            searchSourceBuilder.query(queryBuilder);
            // 聚合查询
            TermsAggregationBuilder requestAgg;
            if (CommonUtil.equals(messageType, "1")) {
                requestAgg = AggregationBuilders.terms("request").field("request_url.keyword").size(viewSize);
            } else {
                requestAgg = AggregationBuilders.terms("request").field("class_method.keyword").size(viewSize);
            }
//            requestAgg.order(Terms.Order.aggregation("_count", true));
            requestAgg.subAggregation(AggregationBuilders.avg("avg_num").field("cost_time"));  // 请求时长平均值
            requestAgg.subAggregation(AggregationBuilders.max("max_num").field("cost_time"));  // 请求时长最大值
            requestAgg.subAggregation(AggregationBuilders.min("min_num").field("cost_time"));  // 请求时长最小值
            searchSourceBuilder.aggregation(requestAgg);
            EsResult<Map<String, Object>> esResult = EsSearch.getEsResult(searchSourceBuilder, queryIndex, queryType);
            MetricAggregation requestAggResult = esResult.getMetricAggregation();
            if (null != requestAggResult) {
                TermsAggregation termsAggregation = requestAggResult.getTermsAggregation("request");
                List<TermsAggregation.Entry> entryList = termsAggregation.getBuckets();
                if (null != entryList && entryList.size() > 0) {
                    total = entryList.size();
                    int i = 1;
                    for (TermsAggregation.Entry entry : entryList) {
                        Map<String, Object> resultMap = new HashMap<>();
                        String key = entry.getKey();
                        Long count = entry.getCount();
                        AvgAggregation avgAggregation = entry.getAvgAggregation("avg_num");
                        Double avgNumber = avgAggregation.getAvg();
                        BigDecimal bigDecimal = new BigDecimal(avgNumber);
                        avgNumber = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

                        MaxAggregation maxAggregation = entry.getMaxAggregation("max_num");
                        Double maxNumber = maxAggregation.getMax();
                        bigDecimal = new BigDecimal(maxNumber);
                        maxNumber = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

                        MinAggregation minAggregation = entry.getMinAggregation("min_num");
                        Double minNumber = minAggregation.getMin();
                        bigDecimal = new BigDecimal(minNumber);
                        minNumber = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

                        resultMap.put("avgNumber", avgNumber);
                        resultMap.put("maxNumber", maxNumber);
                        resultMap.put("minNumber", minNumber);
                        resultMap.put("num", i);
                        resultMap.put("requestUrl", key);
                        resultMap.put("docCount", count);
                        resultList.add(resultMap);
                        i++;
                    }
                }
            }
        } catch (Exception ex) {
            log.error("query error:", ex);
        }
        return JsonModel.newSuccess(resultList, total);
    }


    @GetMapping(value = {"/admin/monitor/messagePageView.htm"})
    public ModelAndView messagePageView() {
        String theDate = LocalDateUtil.localDateFormat(LocalDate.now(), LocalDateUtil.FORMAT_PATTERN3);
        Map<String, Object> result = new HashMap<>();
        result.put("theDate", theDate);
        return new ModelAndView("/admin/messagePageView", result);
    }

    @GetMapping("/admin/monitor/pageView")
    public JsonModel pageView(HttpServletRequest request) {
        String evnName = request.getParameter("evnName");  // 模块名称
        String theDate = request.getParameter("theDate");//获取传入时间
        List<String> keyList = new ArrayList<>();
        List<Long> valueList = new ArrayList<>();
        Map<String, Object> resultMap = new HashMap<>();
        double startScollBar = 20;
        try {
            String EMPTY = " ";
            String EARLY_MIN = "00:00";
            String LATE_MIN = "23:50";
            String EARLY_SECOND = "00:00:00";
            String LATE_SECOND = "23:59:59";
            if (CommonUtil.isNullOrEmpty(theDate)) {
                theDate = LocalDateUtil.localDateFormat(LocalDate.now(), LocalDateUtil.FORMAT_PATTERN3);
            }
            long startTimestamp = LocalDateUtil.getTimestamp((theDate + EMPTY + LATE_SECOND), CommonUtil.defaultDateFormat);
            long endTimestamp = LocalDateUtil.getTimestamp((theDate + EMPTY + EARLY_SECOND), CommonUtil.defaultDateFormat);
            final String resultData = "result_data";
            DateHistogramAggregationBuilder dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram(resultData);
            dateHistogramAggregationBuilder.field("req_time");
            dateHistogramAggregationBuilder.dateHistogramInterval(DateHistogramInterval.minutes(10));
            dateHistogramAggregationBuilder.format("yyyy-MM-dd HH:mm");
            dateHistogramAggregationBuilder.minDocCount(0L);
            String queryIndex = "monitor_message_consumer_" + theDate.replace("-", "");
            String queryType = "monitor_message_consumer";
            String min = theDate + EMPTY + EARLY_MIN + ":00";
            String max = theDate + EMPTY + LATE_MIN + ":00";
            long minTimestamp = LocalDateUtil.getTimestamp(min, CommonUtil.defaultDateFormat);
            long maxTimestamp = LocalDateUtil.getTimestamp(max, CommonUtil.defaultDateFormat);
            ExtendedBounds extendedBounds = new ExtendedBounds(minTimestamp, maxTimestamp);
            dateHistogramAggregationBuilder.extendedBounds(extendedBounds);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(0);
            searchSourceBuilder.aggregation(dateHistogramAggregationBuilder);
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            QueryBuilder messageTypeBuilder = QueryBuilders.termQuery("message_type", "1"); //  只统计请求访问量
            queryBuilder.must(messageTypeBuilder);
            QueryBuilder timeBuilder = QueryBuilders.rangeQuery("req_time").lte(startTimestamp)
                    .gte(endTimestamp);
            queryBuilder.must(timeBuilder);
            if (!CommonUtil.isNullOrEmpty(evnName)) {
                QueryBuilder evnNameBuilder = QueryBuilders.termQuery("evn_name.keyword", evnName); //  只统计请求访问量
                queryBuilder.must(evnNameBuilder);
            }
            searchSourceBuilder.query(queryBuilder);
            EsResult<Map<String, Object>> esResult = EsSearch.getEsResult(searchSourceBuilder, queryIndex, queryType);
            MetricAggregation requestAggResult = esResult.getMetricAggregation();
            if (null != requestAggResult) {
                DateHistogramAggregation dateHistogramAggregation = requestAggResult.getDateHistogramAggregation(resultData);
                List<DateHistogramAggregation.DateHistogram> buckets = dateHistogramAggregation.getBuckets();
                // 遍历返回的桶
                for (DateHistogramAggregation.DateHistogram bucket : buckets) {
                    long docCount = bucket.getCount();
                    long key = bucket.getKey();
                    Date keyDate = new Date(key);
                    String keyString = LocalDateUtil.dateFormat(keyDate, "HH:mm");
                    keyList.add(keyString);
                    valueList.add(docCount);
                }
                startScollBar = getScollBar(min, max);
            }

        } catch (Exception ex) {
            log.error("query error:", ex);
        }
        startScollBar -= 3;
        startScollBar = startScollBar > 95 ? 95 : startScollBar;
        resultMap.put("startScollBar", startScollBar);
        resultMap.put("endScollBar", startScollBar + 5);
        resultMap.put("keyList", keyList);
        resultMap.put("valueList", valueList);
        return JsonModel.newSuccess(resultMap);
    }


    private double getScollBar(String startTime, String endTime) throws ParseException {
        double startScollBar = 20;
        if (null != startTime && !"".equals(startTime) && null != endTime && !"".equals(endTime)) {
            long startTimeTemp = LocalDateUtil.getTimestamp(startTime, "yyyy-MM-dd HH:mm:ss");
            long endTimeTemp = LocalDateUtil.getTimestamp(endTime, "yyyy-MM-dd HH:mm:ss");
            long nowTimeTemp = System.currentTimeMillis();
            double scollBar = (nowTimeTemp - startTimeTemp) / (double) (endTimeTemp - startTimeTemp);
            scollBar = scollBar * 100;
            BigDecimal scollBarDecimal = new BigDecimal(scollBar);
            startScollBar = scollBarDecimal.setScale(0, BigDecimal.ROUND_DOWN).doubleValue();
        }
        return startScollBar;
    }
}
